package com.livsdesign.tools.condition

import android.bluetooth.BluetoothAdapter
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.drawable.Drawable
import android.location.LocationManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import com.livsdesign.tools.condition.Template.*

enum class ConditionState(val positive: Boolean) {
    Grand(true), Denied(false), NeverAck(false), Enable(true), Disable(false)
}

data class ConditionTask(
    val drawable: Drawable?,
    val title: String,
    val desc: String,
    val template: Template
)

/**
 * 已经实现的用例
 * @see Permission  权限（Grand, Denied, NeverAck）
 * @see Bluetooth   蓝牙的开关（Enable, Disable）
 * @see LocationToggle 位置信息的开关（Enable, Disable）
 *
 * 自定义用例
 * @see Other
 */
sealed class Template : Behavior {

    ///////////////////////////////////////////////////////////////////////////
    // Permission
    ///////////////////////////////////////////////////////////////////////////
    class Permission(private val permission: String, activityOrFragment: Any) :
        Template(), Behavior, LifecycleEventObserver {

        val context = when (activityOrFragment) {
            is Fragment -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment.requireContext()
            }
            is FragmentActivity -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment
            }
            else -> throw IllegalArgumentException("Param 'activityOrFragment' must be Fragment,FragmentActivity")
        }

        private val utils = PermissionUtils(activityOrFragment)

        private fun checkState(): ConditionState {
            return if (utils.checkPermissions(permission)) ConditionState.Grand else ConditionState.Denied
        }

        override val mState = MutableLiveData<ConditionState>()

        override fun check() {
            mState.postValue(checkState())
        }

        override fun request() {
            when (val currentState = mState.value ?: checkState()) {
                ConditionState.Denied -> requestWhenDenied()
                ConditionState.NeverAck -> requestWhenNeverAck()
                else -> mState.postValue(currentState)
            }
        }

        /**
         * 当权限申请为NeverAck情况下
         */
        private fun requestWhenNeverAck() {
            val intent = Intent()
            intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
            intent.data = Uri.parse("package:" + context.packageName)
            context.startActivity(intent)
        }

        /**
         * 当权限申请为拒绝情况下
         */
        private fun requestWhenDenied() {
            utils.requestPermission(permission) { isGrand, neverAck ->
                val value = if (isGrand) {
                    ConditionState.Grand
                } else {
                    if (neverAck) ConditionState.NeverAck else ConditionState.Denied
                }
                mState.postValue(value)
                if (neverAck) {
                    request()
                }
            }
        }

        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_RESUME) {
                check()
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Bluetooth
    ///////////////////////////////////////////////////////////////////////////
    class Bluetooth(activityOrFragment: Any) : Template(), Behavior,
        LifecycleEventObserver {
        override val mState = MutableLiveData<ConditionState>()

        private val blueAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()

        val context: Context = when (activityOrFragment) {
            is Fragment -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment.requireContext()
            }
            is FragmentActivity -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment
            }
            else -> throw IllegalArgumentException("Param 'activityOrFragment' must be Fragment, FragmentActivity")
        }

        override fun check() {
            val value =
                if (blueAdapter.isEnabled) ConditionState.Enable else ConditionState.Disable
            mState.postValue(value)
        }

        override fun request() {
            if (!blueAdapter.isEnabled) {
                val state =
                    if (blueAdapter.enable()) ConditionState.Enable else ConditionState.Disable
                mState.postValue(state)
            }
        }

        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            when (event) {
                Lifecycle.Event.ON_CREATE -> registerChanged()
                Lifecycle.Event.ON_RESUME -> check()
                Lifecycle.Event.ON_DESTROY -> unregisterChanged()
                else -> {
                }
            }
        }

        private fun registerChanged() {
            val intentFilter = IntentFilter()
            intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
            context.registerReceiver(receiver, intentFilter)
        }

        private fun unregisterChanged() {
            context.unregisterReceiver(receiver)
        }

        private val receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                when (intent.action ?: return) {
                    BluetoothAdapter.ACTION_STATE_CHANGED -> check()
                }
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // LocationToggle
    ///////////////////////////////////////////////////////////////////////////
    class LocationToggle(private val activityOrFragment: Any) : Template(), Behavior,
        LifecycleEventObserver {
        override val mState = MutableLiveData<ConditionState>()

        val context: Context = when (activityOrFragment) {
            is Fragment -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment.requireContext()
            }
            is FragmentActivity -> {
                activityOrFragment.lifecycle.addObserver(this)
                activityOrFragment
            }
            else -> throw IllegalArgumentException("Param 'activityOrFragment' must be Fragment, FragmentActivity")
        }

        override fun check() {
            val value = if (hasLocationOn()) ConditionState.Enable else ConditionState.Disable
            mState.postValue(value)
        }

        private fun hasLocationOn(): Boolean {
            val locationManager =
                context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                locationManager?.isLocationEnabled ?: false
            } else {
                val locationMode = try {
                    Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE)
                } catch (e: Settings.SettingNotFoundException) {
                    e.printStackTrace()
                    return false
                }
                locationMode != Settings.Secure.LOCATION_MODE_OFF
            }
        }

        private var launcher: ActivityResultLauncher<Int>? = null
        override fun request() {
            if (!hasLocationOn()) {
                launcher?.launch(100)
            }
        }


        /**
         * [自定义协议](https://developer.android.google.cn/training/basics/intents/result#custom)
         */
        class SetLocation : ActivityResultContract<Int, Int?>() {

            override fun createIntent(context: Context, resultCode: Int) =
                Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS).apply {
                    flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
                }

            override fun parseResult(resultCode: Int, result: Intent?): Int {
                return 0
            }
        }

        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            when (event) {
                Lifecycle.Event.ON_CREATE -> registerChanged()
                Lifecycle.Event.ON_RESUME -> check()
                Lifecycle.Event.ON_DESTROY -> unregisterChanged()
                else -> {
                }
            }
        }

        private fun registerChanged() {
            val intentFilter = IntentFilter()
            intentFilter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION)
            context.registerReceiver(receiver, intentFilter)
            //registerForActivityResult必须在OnAttach或者Created中注册，否则报错
            launcher = when (activityOrFragment) {
                is Fragment -> activityOrFragment.registerForActivityResult(SetLocation()) {
                    check()
                }
                is FragmentActivity -> activityOrFragment.registerForActivityResult(SetLocation()) {
                    check()
                }
                else -> throw java.lang.IllegalArgumentException("context must be Fragment,FragmentActivity")
            }
        }

        private fun unregisterChanged() {
            context.unregisterReceiver(receiver)
        }

        private val receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                when (intent.action ?: return) {
                    LocationManager.PROVIDERS_CHANGED_ACTION -> check()
                }
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Other
    ///////////////////////////////////////////////////////////////////////////
    class Other(lifecycle: Lifecycle, private val behavior: Behavior) : Template(), Behavior,
        LifecycleEventObserver {

        init {
            lifecycle.addObserver(this)
        }

        override val mState: MutableLiveData<ConditionState> = behavior.mState
        override fun check() = behavior.check()
        override fun request() = behavior.request()
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_RESUME) {
                check()
            }
        }
    }
}

interface Behavior {
    val mState: MutableLiveData<ConditionState>
    fun check()
    fun request()
}